﻿using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClientApp
{
    /// <summary>
    /// 管道通信客户端 (.NET 8 兼容版)
    /// </summary>
    public class NamedPipeClient : IDisposable
    {
        private readonly string _serverName;
        private readonly string _pipeName;
        private NamedPipeClientStream? _pipeClient;
        private CancellationTokenSource? _cts;
        private bool _disposed;
        private bool _isConnecting;

        /// <summary>
        /// 当前连接状态
        /// </summary>
        public bool IsConnected => _pipeClient?.IsConnected == true;

        /// <summary>
        /// 当连接成功时触发
        /// </summary>
        public event EventHandler? Connected;

        /// <summary>
        /// 当断开连接时触发
        /// </summary>
        public event EventHandler? Disconnected;

        /// <summary>
        /// 当接收到消息时触发
        /// </summary>
        public event EventHandler<string>? MessageReceived;

        /// <summary>
        /// 当发生错误时触发
        /// </summary>
        public event EventHandler<Exception>? ErrorOccurred;

        public NamedPipeClient(string serverName, string pipeName)
        {
            _serverName = serverName ?? throw new ArgumentNullException(nameof(serverName));
            _pipeName = pipeName ?? throw new ArgumentNullException(nameof(pipeName));
        }

        /// <summary>
        /// 连接到管道服务
        /// </summary>
        /// <param name="timeout">连接超时时间（毫秒）</param>
        public async Task ConnectAsync(int timeout = 5000)
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(NamedPipeClient));

            if (_isConnecting || IsConnected)
                throw new InvalidOperationException("已连接或正在连接");

            _isConnecting = true;
            _cts = new CancellationTokenSource();

            try
            {
                _pipeClient = new NamedPipeClientStream(
                    _serverName,
                    _pipeName,
                    PipeDirection.InOut,
                    PipeOptions.Asynchronous);

                await _pipeClient.ConnectAsync(timeout, _cts.Token);

                _isConnecting = false;
                Connected?.Invoke(this, EventArgs.Empty);

                _ = Task.Run(() => ReceiveMessagesAsync(_cts.Token), _cts.Token);
            }
            catch (Exception ex)
            {
                _isConnecting = false;
                ErrorOccurred?.Invoke(this, ex);
                throw;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            if (_pipeClient == null) return;

            _cts?.Cancel();
            _cts?.Dispose();
            _cts = null;

            try
            {
                if (_pipeClient.IsConnected)
                {
                    _pipeClient.Close();
                }
                _pipeClient.Dispose();
            }
            catch { /* 忽略关闭时的异常 */ }
            finally
            {
                _pipeClient = null;
                Disconnected?.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// 发送消息到服务端
        /// </summary>
        public async Task SendMessageAsync(string message)
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(NamedPipeClient));

            if (_pipeClient == null || !_pipeClient.IsConnected)
                throw new InvalidOperationException("未连接到服务");

            try
            {
                byte[] buffer = Encoding.UTF8.GetBytes(message);
                await _pipeClient.WriteAsync(buffer, 0, buffer.Length);
                await _pipeClient.FlushAsync();
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
                throw;
            }
        }

        private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
        {
            if (_pipeClient == null) return;

            var buffer = new byte[4096];

            try
            {
                while (!cancellationToken.IsCancellationRequested &&
                       _pipeClient.IsConnected)
                {
                    int bytesRead = await _pipeClient.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
                    if (bytesRead == 0) break; // 服务端断开

                    string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    MessageReceived?.Invoke(this, message);
                }
            }
            catch (OperationCanceledException)
            {
                // 正常取消
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
            }
            finally
            {
                Disconnect();
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing)
            {
                Disconnect();
                _cts?.Dispose();
            }

            _disposed = true;
        }

        ~NamedPipeClient() => Dispose(false);
    }
}
